A static field in a generic type is not shared among instances of different closed constructed types, thus
LengthLimitedSingletonCollection<int>.instances
and LengthLimitedSingletonCollection<string>.instances
will
point to different objects, even though instances
is seemingly shared among all LengthLimitedSingletonCollection<>
generic classes.
If you need to have a static field shared among instances with different generic arguments, define a non-generic base class to store your static
members, then set your generic type to inherit from the base class.
Noncompliant code example
public class LengthLimitedSingletonCollection<T> where T : new()
{
protected const int MaxAllowedLength = 5;
protected static Dictionary<Type, object> instances = new Dictionary<Type, object>(); // Noncompliant
public static T GetInstance()
{
object instance;
if (!instances.TryGetValue(typeof(T), out instance))
{
if (instances.Count >= MaxAllowedLength)
{
throw new Exception();
}
instance = new T();
instances.Add(typeof(T), instance);
}
return (T)instance;
}
}
Compliant solution
public class SingletonCollectionBase
{
protected static Dictionary<Type, object> instances = new Dictionary<Type, object>();
}
public class LengthLimitedSingletonCollection<T> : SingletonCollectionBase where T : new()
{
protected const int MaxAllowedLength = 5;
public static T GetInstance()
{
object instance;
if (!instances.TryGetValue(typeof(T), out instance))
{
if (instances.Count >= MaxAllowedLength)
{
throw new Exception();
}
instance = new T();
instances.Add(typeof(T), instance);
}
return (T)instance;
}
}
Exceptions
If the static field or property uses a type parameter, then the developer is assumed to understand that the static member is not shared among the
closed constructed types.
public class Cache<T>
{
private static Dictionary<string, T> CacheDictionary { get; set; } // Compliant
}